home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d892.lha / Indent / source / source.lha / backup.c < prev    next >
C/C++ Source or Header  |  1993-06-24  |  11KB  |  428 lines

  1. /* backup.c -- make Emacs style backup file names
  2.    Copyright (C) 1992 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it without restriction.
  6.  
  7.    This program is distributed in the hope that it will be useful,
  8.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10.  
  11.  
  12.  
  13.    GNU/Emacs style backups --
  14.    This behaviour is controlled by two environment variables,
  15.    VERSION_CONTROL and SIMPLE_BACKUP_SUFFIX.
  16.  
  17.    VERSION_CONTROL determines what kinds of backups are made.  If it's
  18.    value is "numbered", then the first modification of some file
  19.    "eraserhead.c" will yield a backup file "eraserhead.c.~1~", the
  20.    second modification will yield "eraserhead.c.~2~", and so on.  It
  21.    does not matter if the version numbers are not a sequence;  the next
  22.    version will be one greater than the highest in that directory.
  23.  
  24.    If the value of VERSION_CONTROL is "numbered_existing", then such
  25.    numbered backups will be made if there are already numbered backup
  26.    versions of the file.  Otherwise, the backup name will be that of
  27.    the original file with "~" (tilde) appended.  E.g., "eraserhead.c~".
  28.  
  29.    If the value of VERSION_CONTROL is "simple", then the backup name
  30.    will be that of the original file with "~" appended, regardless of
  31.    whether or not there exist numbered versions in the directory.
  32.  
  33.    For simple backups, the value of SIMPLE_BACKUP_SUFFIX will be used
  34.    rather than "~" if it is set.
  35.  
  36.    If VERSION_CONTROL is unset, "numbered_existing" is assumed.  For
  37.    Emacs lovers, "nil" is equivalent to "numbered_existing" and "t" is
  38.    equivalent to "numbered".
  39.  
  40.    Finally, if VERSION_CONTROL is "none" or "never", backups are not
  41.    made.  I suggest you avoid this behaviour. */
  42.  
  43. /* Written by jla, based on code from djm (see `patch') */
  44.  
  45. #include "sys.h"
  46. #include "backup.h"
  47. #include <ctype.h>
  48.  
  49. #ifndef isascii
  50. #define ISDIGIT(c) (isdigit ((unsigned char) (c)))
  51. #else
  52. #define ISDIGIT(c) (isascii (c) && isdigit (c))
  53. #endif
  54.  
  55. #ifndef NODIR
  56.  
  57. #include <sys/types.h>
  58.  
  59. #ifdef DIRENT
  60. #include <dirent.h>
  61. #ifdef direct
  62. #undef direct
  63. #endif
  64. #define direct dirent
  65. #define NLENGTH(direct) (strlen((direct)->d_name))
  66. #else /* !DIRENT */
  67. #define NLENGTH(direct) ((direct)->d_namlen)
  68. #ifdef USG
  69. #ifdef SYSNDIR
  70. #include <sys/ndir.h>
  71. #else /* !SYSNDIR */
  72. #include <ndir.h>
  73. #endif /* !SYSNDIR */
  74. #else /* !USG */
  75. #include <sys/dir.h>
  76. #endif /* !USG */
  77. #endif /* !DIRENT */
  78. #ifdef AMIGA
  79. #define direct dirent
  80. #endif /* AMIGA */
  81.  
  82. #if defined (HAVE_UNISTD_H)
  83. #include <unistd.h>
  84. #endif
  85.  
  86. #if defined (_POSIX_VERSION)    /* Might be defined in unistd.h.  */
  87. /* POSIX does not require that the d_ino field be present, and some
  88.    systems do not provide it. */
  89. #define REAL_DIR_ENTRY(dp) 1
  90. #else
  91. #define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
  92. #endif
  93.  
  94. #else /* NODIR */
  95. #define generate_backup_filename(v,f) simple_backup_name((f))
  96. #endif /* NODIR */
  97.  
  98. #ifdef AMIGA
  99. #define SYS_BACKUP_SUFFIX "!"
  100. #define BACKUP_SUFFIX_STR "!"
  101. #define BACKUP_SUFFIX_CHAR '!'
  102. #define BACKUP_SUFFIX_FORMAT "%s.!%d!"
  103. #endif /* AMIGA */
  104.  
  105. #ifndef SYS_BACKUP_SUFFIX
  106. #define SYS_BACKUP_SUFFIX "~"
  107. #endif
  108.  
  109. #ifndef BACKUP_SUFFIX_STR
  110. #define BACKUP_SUFFIX_STR    "~"
  111. #endif
  112.  
  113. #ifndef BACKUP_SUFFIX_CHAR
  114. #define BACKUP_SUFFIX_CHAR   '~'
  115. #endif
  116.  
  117. #ifndef BACKUP_SUFFIX_FORMAT
  118. #define BACKUP_SUFFIX_FORMAT "%s.~%d~"
  119. #endif
  120.  
  121.  
  122. /* Default backup file suffix to use */
  123. static char *simple_backup_suffix = SYS_BACKUP_SUFFIX;
  124.  
  125. /* What kinds of backup files to make -- see
  126.    table `version_control_values' below. */
  127. enum backup_mode version_control = unknown;
  128.  
  129.  
  130. /* Construct a simple backup name for PATHNAME by appending
  131.    the value of `simple_backup_suffix'. */
  132.  
  133. static char *
  134. simple_backup_name (pathname)
  135.      char *pathname;
  136. {
  137.   char *backup_name;
  138.  
  139.   backup_name = xmalloc (strlen (pathname)
  140.              + strlen (simple_backup_suffix) + 2);
  141.   sprintf (backup_name, "%s%s", pathname, simple_backup_suffix);
  142.   return backup_name;
  143. }
  144.  
  145. #ifndef NODIR
  146. /* If DIRENTRY is a numbered backup version of file BASE, return
  147.    that number.  BASE_LENGTH is the string length of BASE. */
  148.  
  149. static int
  150. version_number (base, direntry, base_length)
  151.      char *base;
  152.      char *direntry;
  153.      int base_length;
  154. {
  155.   int version;
  156.   char *p;
  157.  
  158.   version = 0;
  159.   if (!strncmp (base, direntry, base_length)
  160.       && ISDIGIT (direntry[base_length + 2]))
  161.     {
  162.       for (p = &direntry[base_length + 2]; ISDIGIT (*p); ++p)
  163.     version = version * 10 + *p - '0';
  164.       if (p[0] != BACKUP_SUFFIX_CHAR || p[1])
  165.     version = 0;
  166.     }
  167.  
  168.   return version;
  169. }
  170.  
  171.  
  172. /* Return the highest version of file FILENAME in directory
  173.    DIRNAME.  Return 0 if there are no numbered versions. */
  174.  
  175. static int
  176. highest_version (filename, dirname)
  177.      char *filename, *dirname;
  178. {
  179.   DIR *dirp;
  180.   struct direct *dp;
  181.   int highest_version;
  182.   int this_version;
  183.   int file_name_length;
  184.  
  185.   dirp = opendir (dirname);
  186.   if (!dirp)
  187.     return 0;
  188.  
  189.   highest_version = 0;
  190.   file_name_length = strlen (filename);
  191.  
  192.   while ((dp = readdir (dirp)) != 0)
  193.     {
  194.       if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) <= file_name_length + 2)
  195.     continue;
  196.  
  197.       this_version = version_number (filename, dp->d_name, file_name_length);
  198.       if (this_version > highest_version)
  199.     highest_version = this_version;
  200.     }
  201.  
  202.   closedir (dirp);
  203.   return highest_version;
  204. }
  205.  
  206.  
  207. /* Return the highest version number for file PATHNAME.  If there
  208.    are no backups, or only a simple backup, return 0. */
  209.  
  210. static int
  211. max_version (pathname)
  212.      char *pathname;
  213. {
  214.   register char *p;
  215.   register char *filename;
  216.   int pathlen = strlen (pathname);
  217.   int version;
  218.  
  219.   p = pathname + pathlen - 1;
  220. #ifdef AMIGA
  221.   while (p > pathname && *p != '/' && *p != ':')
  222.     p--;
  223.   if (*p == '/')
  224.     {
  225.       int dirlen = p - pathname;
  226.       register char *dirname;
  227.  
  228.       filename = p + 1;
  229.       dirname = xmalloc (dirlen + 1);
  230.       strncpy (dirname, pathname, (dirlen));
  231.       dirname[dirlen] = '\0';
  232.       version = highest_version (filename, dirname);
  233.       free (dirname);
  234.       return version;
  235.     }
  236.   else if (*p == ':')
  237.     {
  238.       int dirlen = p - pathname + 1;
  239.       register char *dirname;
  240.  
  241.       filename = p + 1;
  242.       dirname = xmalloc (dirlen + 1);
  243.       strncpy (dirname, pathname, (dirlen));
  244.       dirname[dirlen] = '\0';
  245.       version = highest_version (filename, dirname);
  246.       free (dirname);
  247.       return version;
  248.     }
  249. #else /* !AMIGA */
  250.   while (p > pathname && *p != '/')
  251.     p--;
  252.  
  253.   if (*p == '/')
  254.     {
  255.       int dirlen = p - pathname;
  256.       register char *dirname;
  257.  
  258.       filename = p + 1;
  259.       dirname = xmalloc (dirlen + 1);
  260.       strncpy (dirname, pathname, (dirlen));
  261.       dirname[dirlen] = '\0';
  262.       version = highest_version (filename, dirname);
  263.       free (dirname);
  264.       return version;
  265.     }
  266. #endif /* !AMIGA */
  267.  
  268.   filename = pathname;
  269. #ifdef AMIGA
  270.   version = highest_version (filename, "");
  271. #else /* !AMIGA */
  272.   version = highest_version (filename, ".");
  273. #endif /* !AMIGA */
  274.   return version;
  275. }
  276.  
  277.  
  278. /* Generate a backup filename for PATHNAME, dependent on the
  279.    value of VERSION_CONTROL. */
  280.  
  281. static char *
  282. generate_backup_filename (version_control, pathname)
  283.      enum backup_mode version_control;
  284.      char *pathname;
  285. {
  286.   int last_numbered_version;
  287.   char *backup_name;
  288.  
  289.   if (version_control == none)
  290.     return 0;
  291.  
  292.   if (version_control == simple)
  293.     return simple_backup_name (pathname);
  294.  
  295.   last_numbered_version = max_version (pathname);
  296.   if (version_control == numbered_existing
  297.       && last_numbered_version == 0)
  298.     return simple_backup_name (pathname);
  299.  
  300.   last_numbered_version++;
  301.   backup_name = xmalloc (strlen (pathname) + 16);
  302.   if (!backup_name)
  303.     return 0;
  304.  
  305.   sprintf (backup_name, BACKUP_SUFFIX_FORMAT, pathname,
  306.        (int) last_numbered_version);
  307.   return backup_name;
  308. }
  309.  
  310. #endif /* !NODIR */
  311.  
  312. static struct version_control_values values[] =
  313. {
  314.   {none, "never"},        /* Don't make backups. */
  315.   {simple, "simple"},        /* Only simple backups */
  316.   {numbered_existing, "existing"},    /* Numbered if they already exist */
  317.   {numbered_existing, "nil"},    /* Ditto */
  318.   {numbered, "numbered"},    /* Numbered backups */
  319.   {numbered, "t"},        /* Ditto */
  320.   {unknown, 0}            /* Initial, undefined value. */
  321. };
  322.  
  323.  
  324. extern char *getenv ();
  325.  
  326. /* Determine the value of `version_control' by looking in the
  327.    environment variable "VERSION_CONTROL".  Defaults to
  328.    numbered_existing. */
  329.  
  330. enum backup_mode
  331. version_control_value ()
  332. {
  333.   char *version;
  334.   struct version_control_values *v;
  335.  
  336.   version = getenv ("VERSION_CONTROL");
  337.   if (version == 0 || *version == 0)
  338.     return numbered_existing;
  339.  
  340.   v = &values[0];
  341.   while (v->name)
  342.     {
  343.       if (strcmp (version, v->name) == 0)
  344.     return v->value;
  345.       v++;
  346.     }
  347.  
  348.   return unknown;
  349. }
  350.  
  351.  
  352. /* Initialize information used in determining backup filenames. */
  353.  
  354. void
  355. initialize_backups ()
  356. {
  357.   char *v = getenv ("SIMPLE_BACKUP_SUFFIX");
  358.  
  359.   if (v && *v)
  360.     simple_backup_suffix = v;
  361. #ifdef NODIR
  362.   version_control = simple;
  363. #else /* !NODIR */
  364.   version_control = version_control_value ();
  365.   if (version_control == unknown)
  366.     {
  367.       fprintf (stderr, "indent:  Strange version-control value\n");
  368.       fprintf (stderr, "indent:  Using numbered-existing\n");
  369.       version_control = numbered_existing;
  370.     }
  371. #endif /* !NODIR */
  372. }
  373.  
  374. /* Prints an error message using `perror' */
  375. extern void sys_error ();
  376.  
  377. /* Make a backup copy of FILE, taking into account version-control.
  378.    See the description at the beginning of the file for details. */
  379.  
  380. void
  381. make_backup (file)
  382.      struct file_buffer *file;
  383. {
  384.   int fd;
  385. #ifndef AMIGA
  386.   register char *p = file->name + strlen (file->name) - 1;
  387. #endif
  388.   char *backup_filename;
  389. #ifndef AMIGA
  390.   char *new_backup_name;
  391. #endif
  392.  
  393.   backup_filename = generate_backup_filename (version_control, file->name);
  394. #ifdef AMIGA
  395.   /* The original code contains a bug here. generate_backup_filename sets
  396.      the return value to NULL if version_control == none. Just do nothing
  397.      in this case. */
  398.   if (! backup_filename)
  399.     {
  400.       if (version_control != none)
  401.         {
  402.           fprintf (stderr, "indent: Can't make backup filename of %s\n", file->name);
  403.           exit (1);
  404.         }
  405.       else
  406.         {
  407.           free (backup_filename);
  408.           return;
  409.         }
  410.     }
  411. #else /* !AMIGA */
  412.   if (!backup_filename)
  413.     {
  414.       fprintf (stderr, "indent: Can't make backup filename of %s", file->name);
  415.       exit (1);
  416.     }
  417. #endif /* !AMIGA */
  418.  
  419.   fd = creat (backup_filename, 0666);
  420.   if (fd < 0)
  421.     sys_error (backup_filename);
  422.   if (write (fd, file->data, file->size) != file->size)
  423.     sys_error (backup_filename);
  424.  
  425.   close (fd);
  426.   free (backup_filename);
  427. }
  428.